package com.paradogs.framework.annotations.serverHandler;

import com.paradogs.framework.annotations.ParadogsAnnotationsHolder;
import com.paradogs.framework.annotations._scan.BaseImportSelector;
import com.paradogs.framework.annotations._scan.BaseScanner;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.classreading.MetadataReader;

import java.lang.reflect.Method;

/**
 * @author: yumi
 * @date: 2023/12/26  10:56
 * @Description: TODO
 */
@Slf4j
public class PRHandlerImport extends BaseImportSelector {

    @Override
    public BaseScanner getScanner(BeanFactory beanFactory) {
        return new PRHandlerScanner((DefaultListableBeanFactory) beanFactory);
    }

    @Override
    public void handle(BeanDefinition beanDefinition) {
        try {
            Class<?> beanClass = Class.forName(beanDefinition.getBeanClassName());

            // 扫描方法
            Method[] methods = beanClass.getDeclaredMethods();
            for (Method method : methods) {

                // 注册 @PRMapping
                registerMapping(method);

                // 注册 @PRHandlerBefore
                registerHandlerBefore(method);

                // 注册 @PRHandlerAfter
                registerHandlerAfter(method);

            }

        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private void registerMapping(Method method) {
        // 计算路由
        PRMapping classMapping = AnnotationUtils.findAnnotation(method.getDeclaringClass(), PRMapping.class);
        PRMapping methodMapping = AnnotationUtils.findAnnotation(method, PRMapping.class);

        if (methodMapping == null) { return; }

        String route = methodMapping.value().trim();
        if (route.equals("")) {
            throw new RuntimeException("Error route mapping: @" + method.getName());
        }

        // 如果有，设置前缀路由
        if (classMapping != null && !classMapping.value().trim().equals("")) {
            route = classMapping.value() + "." + route;
        }

        if (ParadogsAnnotationsHolder.PRHandlerMap.containsKey(route)) {
            throw new RuntimeException("Duplicate route found: " + route);
        }

        ParadogsAnnotationsHolder.PRHandlerMap.put(route, method);
    }

    public void registerHandlerBefore(Method method) {
        PRHandleBefore anno = AnnotationUtils.findAnnotation(method, PRHandleBefore.class);
        if (anno == null) { return; }
        String route = anno.value().trim();
        if (ParadogsAnnotationsHolder.PRHandlerBeforeMap.containsKey(route)) {
            throw new RuntimeException("Duplicate @PRHandleBefore route found: " + route);
        }
        ParadogsAnnotationsHolder.PRHandlerBeforeMap.put(route, method);
    }

    public void registerHandlerAfter(Method method) {
        PRHandleAfter anno = AnnotationUtils.findAnnotation(method, PRHandleAfter.class);
        if (anno == null) { return; }
        String route = anno.value().trim();
        if (ParadogsAnnotationsHolder.PRHandlerAfterMap.containsKey(route)) {
            throw new RuntimeException("Duplicate @PRHandleAfter route found: " + route);
        }
        ParadogsAnnotationsHolder.PRHandlerAfterMap.put(route, method);
    }

    public static class PRHandlerScanner extends BaseScanner {
        public PRHandlerScanner(BeanDefinitionRegistry registry) {
            super(registry);
        }
        @Override
        protected boolean isCandidateComponent(MetadataReader metadataReader) {
            return metadataReader.getAnnotationMetadata().hasAnnotation(PRHandler.class.getName());
        }
        @Override
        protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
            return !beanDefinition.getMetadata().isInterface()
                    && !beanDefinition.getMetadata().isAnnotation()
                    && beanDefinition.getMetadata().hasAnnotation(PRHandler.class.getName());
        }
    }
}
